package labox.innovation.gameserver.model.actor;

import java.util.Collection;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import labox.innovation.config.Config;
import labox.innovation.gameserver.ai.CtrlIntention;
import labox.innovation.gameserver.ai.L2CharacterAI;
import labox.innovation.gameserver.ai.L2SummonAI;
import labox.innovation.gameserver.datatables.Experience;
import labox.innovation.gameserver.geodata.GeoData;
import labox.innovation.gameserver.model.FuzeWorld;
import labox.innovation.gameserver.model.L2ItemInstance;
import labox.innovation.gameserver.model.L2Object;
import labox.innovation.gameserver.model.L2Party;
import labox.innovation.gameserver.model.L2Skill;
import labox.innovation.gameserver.model.SceneRegion;
import labox.innovation.gameserver.model.L2Skill.SkillTargetType;
import labox.innovation.gameserver.model.actor.L2Attackable.AggroInfo;
import labox.innovation.gameserver.model.actor.instance.FuzeNpcInstance;
import labox.innovation.gameserver.model.actor.instance.FuzePcInstance;
import labox.innovation.gameserver.model.actor.instance.L2PetInstance;
import labox.innovation.gameserver.model.actor.instance.L2SummonInstance;
import labox.innovation.gameserver.model.actor.knownlist.SummonKnownList;
import labox.innovation.gameserver.model.actor.stat.SummonStat;
import labox.innovation.gameserver.model.actor.status.SummonStatus;
import labox.innovation.gameserver.model.itemcontainer.PetInventory;
import labox.innovation.gameserver.network.SystemMessageId;
import labox.innovation.gameserver.network.serverpackets.AbstractNpcInfo;
import labox.innovation.gameserver.network.serverpackets.ActionFailed; //import labox.innovation.gameserver.network.serverpackets.ExPartyPetWindowAdd;
//import labox.innovation.gameserver.network.serverpackets.ExPartyPetWindowDelete;
//import labox.innovation.gameserver.network.serverpackets.ExPartyPetWindowUpdate;
import labox.innovation.gameserver.network.serverpackets.L2GameServerPacket; //import labox.innovation.gameserver.network.serverpackets.PetDelete;
//import labox.innovation.gameserver.network.serverpackets.PetInfo;
//import labox.innovation.gameserver.network.serverpackets.PetItemList;
//import labox.innovation.gameserver.network.serverpackets.PetStatusShow;
//import labox.innovation.gameserver.network.serverpackets.PetStatusUpdate;
import labox.innovation.gameserver.network.serverpackets.DeleteObject;
import labox.innovation.gameserver.network.serverpackets.PetStatusShow;
import labox.innovation.gameserver.network.serverpackets.RelationChanged;
import labox.innovation.gameserver.network.serverpackets.StatusUpdate;
import labox.innovation.gameserver.network.serverpackets.SystemMessage;
import labox.innovation.gameserver.taskmanager.DecayTaskManager;
import labox.innovation.gameserver.templates.chars.NpcTemplate;
import labox.innovation.gameserver.templates.item.L2Weapon;

public abstract class L2Summon extends L2Playable {

	protected static Logger _log = LoggerFactory.getLogger(L2Summon.class.getName());

	private FuzePcInstance _owner;

	private int _attackRange = 36; //Melee range

	/**
	 * 当前跟随状态
	 */
	private boolean _follow = true;

	/**
	 * 上一次的跟随状态
	 */
	private boolean _previousFollowStatus = true;

	public class AIAccessor extends L2Character.AIAccessor {
		protected AIAccessor() {
		}

		public L2Summon getSummon() {
			return L2Summon.this;
		}

		public boolean isAutoFollow() {
			return L2Summon.this.getFollowStatus();
		}

		public void doPickupItem(L2Object object) {
			L2Summon.this.doPickupItem(object);
		}
	}

	public L2Summon(long objectId, NpcTemplate template, FuzePcInstance owner) {
		super(objectId, template);
		setInstanceId(owner.getInstanceId()); //设置于拥有者相同的副本
		_owner = owner;
		setXYInvisible(owner.getX() + 50, owner.getY() + 100);
	}

	@Override
	public void onSpawn() {
		super.onSpawn();
		setFollowStatus(true);
		updateAndBroadcastStatus(0);
		//		getOwner().sendPacket(new RelationChanged(this, getOwner().getRelation(getOwner()), false));
		//		for (FuzePcInstance player : getOwner().getKnownList().getKnownPlayers().values())
		//			player.sendPacket(new RelationChanged(this, getOwner().getRelation(player), isAutoAttackable(player)));
		//
		//		L2Party party = getOwner().getParty();
		//		if (party != null) {
		//			party.broadcastToPartyMembers(getOwner(), new ExPartyPetWindowAdd(this));
		//		}
	}

	@Override
	public final SummonKnownList getKnownList() {
		return (SummonKnownList) _knownList;
	}

	@Override
	public void initKnownList() {
		setKnownList(new SummonKnownList(this));
	}

	@Override
	public SummonStat getStat() {
		return (SummonStat) _stat;
	}

	@Override
	public void initCharStat() {
		setStat(new SummonStat(this));
	}

	@Override
	public SummonStatus getStatus() {
		return (SummonStatus) _status;
	}

	@Override
	public void initCharStatus() {
		setStatus(new SummonStatus(this));
	}

	@Override
	public void initAI() {
		_ai = new L2SummonAI(new L2Summon.AIAccessor());
	}

	@Override
	public NpcTemplate getTemplate() {
		return (NpcTemplate) _template;
	}

	// 这里定义了召唤物的类型，1是召唤物，2是宠物
	public abstract int getSummonType();

	/**
	 * 停止所有身上的效果
	 */
	@Override
	public final void stopAllEffects() {
		super.stopAllEffects();
		updateAndBroadcastStatus(1);
	}

	/**
	 * 停止身上的除了那些死亡后还存在的所有效果
	 */
	@Override
	public final void stopAllEffectsExceptThoseThatLastThroughDeath() {
		super.stopAllEffectsExceptThoseThatLastThroughDeath();
		updateAndBroadcastStatus(1);
	}

	/**
	 * 更新异常效果
	 */
	@Override
	public void updateAbnormalEffect() {
		Collection<FuzePcInstance> plrs = getKnownList().getKnownPlayers().values();

		//		for (FuzePcInstance player : plrs)
		//			player.sendPacket(new AbstractNpcInfo.SummonInfo(this, player, 1));

	}

	/**
	 * @return Returns the mountable.
	 */
	public boolean isMountable() {
		return false;
	}

	@Override
	public void onAction(FuzePcInstance player) {
		// Aggression target lock effect
		if (player.isLockedTarget() && player.getLockedTarget() != this) {//检查锁定的对象是不是自己
			player.sendPacket(new SystemMessage(SystemMessageId.FAILED_CHANGE_TARGET));
			return;
		}

		if (player.getTarget() != this) {
			player.setTarget(this);
			//sends HP/MP status of the summon to other characters
			StatusUpdate su = new StatusUpdate(_objectId);
			su.addAttribute(StatusUpdate.HP, getCurrentHpRadio());
			su.addAttribute(StatusUpdate.MP, getCurrentMpRadio());
			player.sendPacket(su);

			if (player == _owner) {//如果是主人请求
				player.sendPacket(new PetStatusShow(this));
				return;
			}
		}

		if (player.getTarget() == this) {
			if (isAutoAttackable(player)) {
				player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
				player.onActionRequest();
			}
		}
	}

	public final int getKarma() {
		return getOwner() != null ? getOwner().getKarma() : 0;
	}

	public final byte getPvpFlag() {
		return getOwner() != null ? getOwner().getPvpFlag() : 0;
	}

	public final FuzePcInstance getOwner() {
		return _owner;
	}

	public final int getNpcId() {
		return getTemplate()._id;
	}

	public int getMaxLoad() {
		return 0;
	}

	public void followOwner() {
		setFollowStatus(true);
	}

	@Override
	public boolean doDie(L2Character killer) {
		if (!super.doDie(killer))
			return false;

		FuzePcInstance owner = getOwner();
		if (owner != null) {//当召唤物死亡时，要把怪物对召唤物的仇恨值转移到他的主人身上（因为最后的经验分配是按攻击输出分配的）
			Collection<L2Character> KnownTarget = getKnownList().getKnownCharacters().values();
			for (L2Character TgMob : KnownTarget) {
				// get the mobs which have aggro on the this instance
				if (TgMob instanceof L2Attackable) {//检查有没有仇恨列表在这个实例上
					if (((L2Attackable) TgMob).isDead())
						continue;

					AggroInfo info = ((L2Attackable) TgMob).getAggroList().get(this);
					if (info != null)
						((L2Attackable) TgMob).addDamageHate(owner, info._damage, info._hate);
				}
			}
		}
		DecayTaskManager.getInstance().addDecayTask(this);
		return true;
	}

	/**
	 * 腐烂处理
	 */
	@Override
	public void onDecay() {
		deleteMe(_owner);
	}

	@Override
	public void broadcastStatusUpdate() {
		updateAndBroadcastStatus(1);
	}

	public void deleteMe(FuzePcInstance owner) {
		stopAllEffects();
		getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
		getStatus().stopRegeneration();
		owner.sendPacket(new DeleteObject(this));

		//pet will be deleted along with all his items
		if (getInventory() != null) {
			getInventory().destroyAllItems("pet deleted", getOwner(), this);
		}
		decayMe();
		owner.setPet(null);
		setTarget(null);
		FuzeWorld.getInstance().exitWorld(this);
	}

	public void unSummon(FuzePcInstance owner) {
		if (isVisible() && !isDead()) {
			store();
			giveAllToOwner();
			deleteMe(owner);
		}
	}

	public int getAttackRange() {
		return _attackRange;
	}

	public void setAttackRange(int range) {
		_attackRange = range;
	}

	public void setFollowStatus(boolean state) {
		_follow = state;
		if (_follow)
			getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, getOwner());
		else
			getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null);
	}

	public boolean getFollowStatus() {
		return _follow;
	}

	@Override
	public boolean isAutoAttackable(L2Character attacker) {
		return _owner.isAutoAttackable(attacker);
	}

	public long getControlItemId() {
		return 0;
	}

	public L2Weapon getActiveWeapon() {
		return null;
	}

	@Override
	public PetInventory getInventory() {
		return null;
	}

	protected void doPickupItem(L2Object object) {
	}

	public void giveAllToOwner() {
	}

	public void store() {
	}

	@Override
	public L2ItemInstance getActiveWeaponInstance() {
		return null;
	}

	@Override
	public L2Weapon getActiveWeaponItem() {
		return null;
	}

	@Override
	public L2ItemInstance getSecondaryWeaponInstance() {
		return null;
	}

	@Override
	public L2Weapon getSecondaryWeaponItem() {
		return null;
	}

	/**
	 * Return True if the L2Summon is invulnerable or if the summoner is in spawn protection.<BR>
	 * <BR>
	 */
	@Override
	public boolean isInvul() {//是否无敌状态
		return super.isInvul() || isTeleporting() || getOwner().isSpawnProtected();
	}

	/**
	 * Return the L2Party object of its L2PcInstance owner or null.<BR>
	 * <BR>
	 */
	@Override
	public L2Party getParty() {
		if (_owner == null)
			return null;
		else
			return _owner.getParty();
	}

	/**
	 * Return True if the L2Character has a Party in progress.<BR>
	 * <BR>
	 */
	@Override
	public boolean isInParty() {
		if (_owner == null)
			return false;
		else
			return _owner.getParty() != null;
	}

	/**
	 * Check if the active L2Skill can be casted.<BR>
	 * <BR>
	 * 
	 * <B><U> Actions</U> :</B><BR>
	 * <BR>
	 * <li>Check if the target is correct</li> <li>Check if the target is in the skill cast range</li> <li>Check if the summon owns enough HP and MP to cast the skill</li> <li>Check if all skills are enabled and this skill is enabled</li><BR>
	 * <BR>
	 * <li>Check if the skill is active</li><BR>
	 * <BR>
	 * <li>Notify the AI with AI_INTENTION_CAST and target</li><BR>
	 * <BR>
	 * 
	 * @param skill
	 *            The L2Skill to use
	 * @param forceUse
	 *            used to force ATTACK on players
	 * @param dontMove
	 *            used to prevent movement, if not in range
	 * 
	 */
	public void useMagic(L2Skill skill, boolean forceUse, boolean dontMove) {
		if (skill == null || isDead())
			return;

		// 检查如果技能师被动的是不能主动释放的
		if (skill.isPassive()) {
			// just ignore the passive skill request. why does the client send it anyway ??
			return;
		}

		//************************************* Check Target *******************************************

		// Get the target for the skill
		L2Object target = null;

		switch (skill.getTargetType()) {
		// OWNER_PET should be cast even if no target has been found
		case TARGET_OWNER_PET://如果是对主人的
			target = getOwner();
			break;
		// PARTY, AURA, SELF should be cast even if no target has been found
		case TARGET_PARTY:
			//		case TARGET_AURA:
			//		case TARGET_FRONT_AURA:
			//		case TARGET_BEHIND_AURA:
		case TARGET_SELF:
			target = this;
			break;
		default:
			// Get the first target of the list
			target = skill.getFirstOfTargetList(this);
			break;
		}

		// Check the validity of the target
		if (target == null) {
			if (getOwner() != null)
				getOwner().sendPacket(new SystemMessage(SystemMessageId.TARGET_CANT_FOUND));
			return;
		}

		//************************************* Check skill availability *******************************************

		// Check if this skill is enabled (e.g. reuse time)
		if (isSkillDisabled(skill.getId())) {
			if (getOwner() != null) {
				SystemMessage sm = new SystemMessage(SystemMessageId.S1_PREPARED_FOR_REUSE);
				sm.addSkillName(skill);
				getOwner().sendPacket(sm);
			}
			return;
		}

		//************************************* Check Consumables *******************************************

		// Check if the summon has enough MP
		if (getCurrentMp() < skill.getMpConsume()) {
			// Send a System Message to the caster
			if (getOwner() != null)
				getOwner().sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_MP));
			return;
		}

		// Check if the summon has enough HP
		if (getCurrentHp() <= skill.getHpConsume()) {
			// Send a System Message to the caster
			if (getOwner() != null)
				getOwner().sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_HP));
			return;
		}

		//************************************* Check Summon State *******************************************

		//如果是进攻型魔法攻击
		if (skill.isOffensive()) {//如果是攻击魔法
			if (isInsidePeaceZone(this, target) && getOwner() != null && (!getOwner().getAccessLevel().allowPeaceAttack())) {
				// If summon or target is in a peace zone, send a system message TARGET_IN_PEACEZONE
				sendPacket(new SystemMessage(SystemMessageId.TARGET_IN_PEACEZONE));
				return;
			}

			// Check if the target is attackable
			if (!target.isAttackable() && getOwner() != null && (!getOwner().getAccessLevel().allowPeaceAttack())) {
				return;
			}

		}
		getOwner().setCurrentPetSkill(skill, forceUse, dontMove);
		//通知AI进入施法状态
		getAI().setIntention(CtrlIntention.AI_INTENTION_CAST, skill, target);
	}

	@Override
	public void setIsImmobilized(boolean value) {
		super.setIsImmobilized(value);

		if (value) {
			_previousFollowStatus = getFollowStatus();
			// if immobilized temporarly disable follow mode
			if (_previousFollowStatus)
				setFollowStatus(false);
		} else {
			// if not more immobilized restore previous follow mode
			setFollowStatus(_previousFollowStatus);
		}
	}

	public void setOwner(FuzePcInstance newOwner) {
		_owner = newOwner;
	}

	@Override
	public void doCast(L2Skill skill) {
		final FuzePcInstance actingPlayer = getActingPlayer();

		if (!actingPlayer.checkPvpSkill(getTarget(), skill) && !actingPlayer.getAccessLevel().allowPeaceAttack()) {
			// Send a System Message to the L2PcInstance
			actingPlayer.sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT));
			return;
		}

		super.doCast(skill);
	}

	public boolean isInCombat() {
		return getOwner().isInCombat();
	}

	@Override
	public FuzePcInstance getActingPlayer() {
		return getOwner();
	}

	public void updateAndBroadcastStatus(int val) {
		//		getOwner().sendPacket(new PetInfo(this, val));
		//		getOwner().sendPacket(new PetStatusUpdate(this));
		if (isVisible()) {
			broadcastNpcInfo(val);
		}
		L2Party party = this.getOwner().getParty();
		//		if (party != null) {
		//			party.broadcastToPartyMembers(getOwner(), new ExPartyPetWindowUpdate(this));
		//		}
		updateEffectIcons(true);
	}

	public void broadcastNpcInfo(int val) {
		Collection<FuzePcInstance> plrs = getKnownList().getKnownPlayers().values();
		//		for (FuzePcInstance player : plrs) {
		//			try {
		//				if (player == getOwner() && !(this instanceof L2MerchantSummonInstance))
		//					continue;
		//				player.sendPacket(new AbstractNpcInfo.SummonInfo(this, player, val));
		//			} catch (NullPointerException e) {
		//				// ignore it
		//			}
		//		}
	}

	public boolean isHungry() {
		return false;
	}

	@Override
	public final boolean isAttackingNow() {
		return isInCombat();
	}

	public int getWeapon() {
		return 0;
	}

	public int getArmor() {
		return 0;
	}

	public int getPetSpeed() {
		return getTemplate().baseRunSpd;
	}

	@Override
	public void sendInfo(FuzePcInstance activeChar) {
		// Check if the L2PcInstance is the owner of the Pet
		//		if (activeChar == getOwner()) {
		//			//			activeChar.sendPacket(new PetInfo(this, 0));
		//			// The PetInfo packet wipes the PartySpelled (list of active  spells' icons).  Re-add them
		//			updateEffectIcons(true);
		//			if (this instanceof L2PetInstance) {
		//				//				activeChar.sendPacket(new PetItemList((L2PetInstance) this));
		//			}
		//		} else
		activeChar.sendPacket(new AbstractNpcInfo.SummonInfo(this, activeChar));
	}
}
